require("plugin")

plugin.music = {
	new = function(p)
		local self = { plugin = p }
		setmetatable(self, { __index = plugin.music })
		-- self:reloadAll()
		self:reloadPlaylists()
		self:crossFade(common.getConfig("plugin.music.crossfade"))
		return self
	end,
	
	activate = function(self)
		self:buildPlaylist()
		self._status = nil
		self:showPage()
		self.active = true
	end,
	
	deactivate = function(self)
		self.active = false
	end,
	
	destroy = function(self)
		self:pause()
	end,
	
	check = function(self)
		self.plugin.stoicheia:checkCmd(0, "mpc", "version")
	end,
	
	reloadAll = function(self)
		self:clear()
		self:listAll(function(line)
			self:add(line)
		end)
	end,
	
	reloadPlaylists = function(self)
		local playlists = common.getConfig("plugin.music.playlists")
		self:clear()
		for i, playlist in ipairs(playlists) do
			self:load(playlist)
		end
	end,
	
	updateStatus = function(self)
		self.prevStatus = self._status
		self._status = self:status()
		local title, album, artist, time = "", "", "", ""
		if self._status.index ~= nil then
			local index = tonumber(self._status.index)
			local song = self.songs[index]
			if song == nil then
				log("plugin.music", "Unknown song index from MPC status received: %s", self._status.index)
				return
			end
			title = self:getTitle(song)
			function check(str)
				if str ~= nil then return str end
				return common.getResource("unknown")
			end
			local lstatus = common.getResource("song.status." .. self._status.status)
			title = string.format("%s: %s", lstatus, check(title))
			album = string.format("%s: %s", common.getResource("song.album"), check(song.album))
			artist = string.format("%s: %s", common.getResource("song.artist"), check(song.artist))
			local progress = string.format("(%s%%)", self._status.percent)
			-- local progress = self:getProgressBar(tonumber(self._status.percent), 100, 50)
			time = string.format("%s %s %s %s", self._status.time, common.getResource("of"), self._status.length, progress)
		end
		self:setField("title", title)
		self:setField("album", album)
		self:setField("artist", artist)
		self:setField("time", time)
		if self.prevStatus == nil or self.prevStatus.status ~= self._status.status then
			self:setControls(self._status.status == "playing")
		end
	end,
	
	timerEvent = function(self)
		if not self.active then return end
		self:updateStatus()
	end,
	
	getProgressBar = function(self, value, max, size)
		local count = math.floor(size * tonumber(self._status.percent) / max)
		return string.format("[%s>>>%s]", string.rep("-", count), string.rep("-", size - count))
	end,
	
	setField = function(self, id, text)
		self.plugin.stoicheia.gui.pagewin:exec(string.format("setText(%q, %q);", id, text))
	end,
	
	controlEvent = function(self, event)
		if event == "back" then
			self.plugin.stoicheia:showStartPage()
			return
		end
		if event == "play" then
			self:play()
			self:updateStatus()
			return
		end
		if event == "pause" then
			self:pause()
			self:updateStatus()
			return
		end
		if event == "backward" then
			self:seek(-20)
			self:updateStatus()
			return
		end
		if event == "forward" then
			self:seek(20)
			self:updateStatus()
			return
		end
	end,
	
	pageEvent = function(self, event, arg)
		if event == "CLICKED" then
			self:play(tonumber(arg))
			self:play()
			self:updateStatus()
		end
	end,
	
	showPage = function(self)
		self.plugin.stoicheia:showPage("music", function(event, f)
			local sw, sh = self.plugin.stoicheia:getScreenSize()
			if event == "html" then
				local gap = 50
				local ld = math.ceil(f.fontSize * 1.5)
				local top = f:getControlSize() + gap
				local width = sw - (2 * gap) - (2 * f.border)
				f:renderFormLabel("", nil, gap, top, width, "title", false)
				f:renderFormLabel("", nil, gap, top + ld, width, "album", false)
				f:renderFormLabel("", nil, gap, top + (2 * ld), width, "artist", false)
				f:renderFormLabel("", nil, gap, top + (3 * ld), width, "time", false)
				f:beginList(gap, top + (4 * ld) + gap, width, sh - top - (4 * ld) - (2 * f.border) - (3 * gap))
				common.traverse(self.tree, function(node, name, depth, leaf, path, children)
					if name == nil then return end
					local title, notify
					if leaf then
						local song = self.songs[node]
						title = self:getTitle(song)
						notify = node
					else
						title = name
					end
					title = tostring(title)
					f:renderListItem(title, notify, (depth - 1) * 2)
				end, "", nil, function(a, b)
					if type(a) ~= type(b) then
						return type(a) < type(b)
					end
					return a < b
				end)
				f:endList()
			end
		end)
	end,
	
	setControls = function(self, pause)
		local control = "play"
		if pause then control = "pause" end
		self.plugin.stoicheia:setControls(true, "back", control, "backward", "forward")
	end,
	
	mpc = function(self, ...)
		local err = task.execute("mpc", ...)
		if err ~= 0 then
			log("plugin.music", "MPC returns nonzero error code: %d", err)
		end
	end,
	
	mpcr = function(self, handler, ...)
		local f = task.executer("mpc", ...)
		for line in f:lines() do
			handler(line)
		end
		f:close()
	end,
	
	play = function(self, index)
		self:mpc("play", index)
	end,
	
	pause = function(self)
		self:mpc("pause")
	end,
	
	stop = function(self)
		self:mpc("stop")
	end,
	
	status = function(self)
		local f = task.executer("mpc", "--format", "%file%")
		local lines = {}
		for line in f:lines() do lines[#lines + 1] = line end
		f:close()
		local ret = {}
		if #lines == 3 then
			ret.file = lines[1]
			local s = lines[2]
			local dummy, subs = s:gsub("%[(.-)%] -#(.-)/(.-) -([%d:]*)/([%d:]*) -%((.-)%%%)", function(status, index, count, time, length, percent)
				ret.status = status
				ret.index = index
				ret.count = count
				ret.time = time
				ret.length = length
				ret.percent = percent
			end)
			if subs ~= 1 then
				log("plugin.music", "Cannot parse MPC status line %q", s)
			end
		else
			ret.status = "stopped"
		end
		return ret
	end,
	
	playlist = function(self, format, handler)
		self:mpcr(function(line)
			local subs = line:gsub("^#(%d+)%) +(.+)$", function(index, data)
				handler(tonumber(index), data)
			end)
		end, "--format", format, "playlist")
	end,
	
	buildPlaylist = function(self)
		self.tree = {}
		self.songs = {}
		self:playlist("%file%", function(index, path)
			local segs = path:split("/")
			local node = self.tree
			for i, seg in ipairs(segs) do
				if i < #segs then
					if node[seg] == nil then
						node[seg] = {}
					end
					node = node[seg]
				end
			end
			self.songs[index] = { file = segs[#segs] }
			node[#node + 1] = index
		end)
		self:playlist("%title%", function(index, title)
			self.songs[index].title = title
		end)
		self:playlist("%album%", function(index, album)
			self.songs[index].album = album
		end)
		self:playlist("%artist%", function(index, artist)
			self.songs[index].artist = artist
		end)
	end,
	
	seek = function(self, seconds)
		if seconds > 0 then seconds = "+" .. tostring(seconds) end
		self:mpc("seek", seconds)
	end,
	
	getTitle = function(self, song)
		local title = song.title
		if title ~= nil and title ~= "" then return title end
		return song.file:gsub("%..-$", ""):gsub("_", " ")
	end,
	
	listAll = function(self, handler)
		self:mpcr(handler, "listall")
	end,
	
	add = function(self, file)
		self:mpc("add", file)
	end,
	
	clear = function(self)
		self:mpc("clear")
	end,
	
	crossFade = function(self, seconds)
		self:mpc("crossfade", seconds)
	end,
	
	load = function(self, playlist)
		self:mpc("load", playlist)
	end
}


